 //-----------------------------------------------------------------------------
//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   pixel_shader
//File Name     :   tex_uv_cal.v
//Module name   :   tex_uv_cal
//Full name     :   convert tex coordinate from parameter space to texture
//space
//
//Author        :   zha daolu
//Email         :   
//Data          :   2020/5/13
//Version       :   V1.00
//
//Abstract      :   
//                  
//Called  by    :   GPU
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//
//----------------------------------------------------------------------------- 
//

module tex_uv_cal(
    input clk,                     //input clock                                                                                                   
    input rst_n,                   //input reset, low active
    input busy_in,                 //input busy
    input signed [31:0] s,         //input s_trans, 1.3.28                                                                                         
    input signed [31:0] t,         //input t_trans, 1.3.28                                                                                         
    input [1:0] wrap_mode_s,       //s dircetion wrap mode,support: 2'b00 repeat; 2'b01 clamp to edge; 2'b10 clamp to border; 2'b11 mirrored repeat
    input [1:0]  wrap_mode_t,      //t dircetion wrap mode,support: 2'b00 repeat; 2'b01 clamp to edge; 2'b10 clamp to border; 2'b11 mirrored repeat
    input cal_en,                  //input valid                                                                                                   
    input [23:0] tex_width,        //texture width,support up to 2^24-1                                                                            
    input [23:0] tex_height,       //teture height,support up to 2^24-1                                                                            
    output reg [31:0] u,           //output u 24.8                                                                                                 
    output reg [31:0] v,           //output v 24.8                                                                                                 
    output valid,                  //output valid
    output busy_out            //output busy
);
parameter UV_PRECISION = 28;

localparam REPEAT          = 2'b0;
localparam CLAMP_TO_EDGE   = 2'd1;
localparam CLAMP_TO_BORDER = 2'd2;
localparam MIRRORED_REPEAT = 2'd3;

reg [UV_PRECISION - 1:0] s_inter;  //wrapped s 
reg [UV_PRECISION - 1:0] t_inter;  //wrapped t 
wire [31:0] s_integer;
wire [31:0] t_integer;
wire [31:0] s_decimal;
wire [31:0] t_decimal;

// cal integer compment for s t
assign s_integer = {s[31:UV_PRECISION],{UV_PRECISION{1'b0}}};//integer part of s
assign t_integer = {t[31:UV_PRECISION],{UV_PRECISION{1'b0}}};//integer part of t

//cal decimal part for s t
assign s_decimal = s[UV_PRECISION - 1 :0];// - s_integer; //decimal part of s
assign t_decimal = t[UV_PRECISION - 1 :0];// - t_integer; //decimal part of t

//**************************************
//stage 1 cal s t according to wrap mode
//**************************************

//REPEAT mode : s_inter = s_decimal
//CLAMP TO EDGE mode: overflow clamp to [0,1)
//CLAMP TO BORDER mode: overflow clamp to [0,1)
//MIRRORED REPEAT mode: 
//                      s_inter = s_decimal          even s
//                      s_inter = 1 - s_decimal      odd  s
always@(posedge clk or negedge rst_n)
begin
    if(~rst_n)
        begin
            s_inter <= 16'b0;
        end
    else if(cal_en && ~busy_in)
        begin
            case(wrap_mode_s)
                REPEAT:
                    begin                                   
                        s_inter <= s_decimal;
                    end
                        
                CLAMP_TO_EDGE:
                    begin
                        if(s[31])
                            s_inter <= 0;
                        else if(s > 32'hffff)
                            s_inter <= 16'hffff;
                        else
                            s_inter <= s_decimal ;
                    end
                
                CLAMP_TO_BORDER:
                    begin
                        if(s[31])
                            s_inter <= 0;
                        else if(s > 32'hffff)
                            s_inter <= 16'hffff;
                        else
                            s_inter <= s_decimal ;
                    end
                        
                MIRRORED_REPEAT:
                    begin
                        if(s[16])
                            s_inter <= 17'h10000 - s_decimal;
                        else
                            s_inter <= s_decimal;
                    end
            endcase
        end
end


//REPEAT mode : t_inter = t_decimal
//CLAMP TO EDGE mode: overflow clamp to [0,1)
//CLAMP TO BORDER mode: overflow clamp to [0,1)
//MIRRORED REPEAT mode: 
//                      t_inter = t_decimal          even t
//                      t_inter = 1 - t_decimal      odd  t   
always@(posedge clk or negedge rst_n)
begin
    if(~rst_n)
        begin
            t_inter <= 16'b0;
        end
    else if(cal_en && ~busy_in)
        begin
            case(wrap_mode_t)
                REPEAT:
                    begin                                   
                        t_inter <=t_decimal;
                    end
                    
                CLAMP_TO_EDGE:
                    begin
                        if(t[31])
                            t_inter <= 0;
                        else if(t > 32'hffff)
                            t_inter <= 16'hffff;  
                        else
                            t_inter <=t_decimal; 
                    end
                
                CLAMP_TO_BORDER:
                    begin
                        if(t[31])
                            t_inter <= 0;
                        else if(t > 32'hffff)
                            t_inter <= 16'hffff;
                        else
                            t_inter <=t_decimal; 
                    end
                        
                MIRRORED_REPEAT:
                    begin
                        if(t[16])
                            t_inter <= 17'h10000 - t_decimal; 
                        else
                            t_inter <= t_decimal; 
                    end
            endcase
        end
end

reg cal_en_ff1;

always@(posedge clk or negedge rst_n)
begin
    if(~rst_n)
        begin
            cal_en_ff1 <= 1'b0;
        end
    else if(~busy_in)
        begin
            cal_en_ff1 <= cal_en;
        end
end 

//************************************
//stage 2 s * tex_width ,t *tex_height
//************************************

wire [23+UV_PRECISION:0] s_x_w;
wire [23+UV_PRECISION:0] t_x_h;

reg valid_reg;

assign s_x_w = s_inter * tex_width;
assign t_x_h = t_inter * tex_height;


always@(posedge clk or negedge rst_n)
begin
    if(~rst_n)
        begin
            u <= 32'b0;
            v <= 32'b0;
            valid_reg <= 1'b0;
        end
    else if(~busy_in)
        begin
            u <= s_x_w[UV_PRECISION+23:UV_PRECISION-8];
            v <= t_x_h[UV_PRECISION+23:UV_PRECISION-8];       
            valid_reg <= cal_en_ff1;
        end
end

assign valid = valid_reg && ~busy_in;
assign busy_out = busy_in;

endmodule
